package com.example.demo.zaqizabatest.多线程相关;

import java.io.IOException;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @ClassName ThreadPoolExecutorDemo
 * @Author lys4134
 * @Date 2021/09/09 15:10:05
 * @Description ThreadPoolExecutorDemo
 * @Version 1.0
 **/
@SuppressWarnings("AlibabaThreadShouldSetName")
public class ThreadPoolExecutorDemo {

    /**
     * new ThreadPoolExecutor();最多参数的构造方法
     * <p>
     * 1    corePoolSize	int	核心线程池大小   核心线程数定义了最小可以同时运行的线程数量。
     * 2	maximumPoolSize	int	最大线程池大小   当队列中存放的任务达到队列容量的时候，当前可以同时运行的线程数量变为最大线程数。
     * 3	keepAliveTime	long	线程最大空闲时间   当新任务来的时候会先判断当前运行的线程数量是否达到核心线程数，如果达到的话，新任务就会被存放在队列中。
     * 4	unit	TimeUnit	时间单位   参数的时间单位。
     * 5	workQueue	BlockingQueue<Runnable>	线程等待队列  当新任务来的时候会先判断当前运行的线程数量是否达到核心线程数，如果达到的话，新任务就会被存放在队列中。
     * 6	threadFactory	ThreadFactory	线程创建工厂  创建新线程的时候会用到
     * 7	handler	RejectedExecutionHandler	拒绝策略
     */


    /**
     * 自己的理解：
     *  线程池中最多可以容纳maximumPoolSize个线程，还有n个等待线程，n为等待队列的大小，
     *  若已满，则按照拒绝策略RejectedExecutionHandler执行其余任务
     *  首先创建两个线程，然后两个核心线程执行任务1和任务2，任务3和任务4发现等待队列满了，
     *  触发线程扩容，即创建线程3和线程4，任务3和任务4进入线程池，任务5和任务6进入等待队列，
     *  最终任务7-任务10发现最大线程数和等待队列都满了，则被拒绝策略执行
     *
     * 百度理解：
     * 1，由于线程预启动，首先创建了1，2号线程，然后task1，task2被执行；
     * 2，但任务提交没有结束，此时任务task3，task6到达发现核心线程已经满了，进入等待队列；
     * 3，等待队列满后创建任务线程3，4执行任务task3，task6，同时task4，task5进入队列；
     * 4，此时创建线程数（4）等于最大线程数，且队列已满，所以7，8，9，10任务被拒绝；
     * 5，任务执行完毕后回头来执行task4，task5，队列清空
     *
     *
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        int corePoolSize = 2;
        int maximumPoolSize = 4;
        long keepAliveTime = 10;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(2);
        ThreadFactory threadFactory = new NameTreadFactory();
        RejectedExecutionHandler handler = new MyIgnorePolicy();
        ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit,
                workQueue, threadFactory, handler);
        executor.prestartAllCoreThreads(); // 预启动所有核心线程

        for (int i = 1; i <= 10; i++) {
            MyTask task = new MyTask(String.valueOf(i));
            executor.execute(task);
        }

        System.in.read(); //阻塞主线程
    }

    static class NameTreadFactory implements ThreadFactory {

        private final AtomicInteger mThreadNum = new AtomicInteger(1);

        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r, "my-thread-" + mThreadNum.getAndIncrement());
            System.out.println(t.getName() + " has been created");
            return t;
        }

        public void getThread() {
            System.out.println();
            System.out.println();
            System.out.println("NameTreadFactory.getThread");
            System.out.println("mThreadNum = " + mThreadNum);
            System.out.println();
            System.out.println();
        }
    }

    public static class MyIgnorePolicy implements RejectedExecutionHandler {

        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            doLog(r, e);
        }

        private void doLog(Runnable r, ThreadPoolExecutor e) {
            // 可做日志记录等
            System.err.println(r.toString() + " rejected");
        }
    }

    static class MyTask implements Runnable {
        private String name;

        public MyTask(String name) {
            this.name = name;
        }

        @Override
        public void run() {
            try {
                System.out.println(this.toString() + " is running!");
                Thread.sleep(3000); //让任务执行慢点
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        public String getName() {
            return name;
        }

        @Override
        public String toString() {
            return "MyTask [name=" + name + "]";
        }
    }


//    public static void main(String[] args) {
//        ExecutorService fixedExecutorService = Executors.newFixedThreadPool(1);
//        ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) fixedExecutorService;
//        System.out.println(threadPoolExecutor.getMaximumPoolSize());
//        threadPoolExecutor.setCorePoolSize(8);
//
//        ExecutorService singleExecutorService = Executors.newSingleThreadExecutor();
////      运行时异常 java.lang.ClassCastException
////      ThreadPoolExecutor threadPoolExecutor2 = (ThreadPoolExecutor) singleExecutorService;
//    }


    /**
     * corePoolSize与maximumPoolSize相等，即其线程全为核心线程，是一个固定大小的线程池，是其优势；
     * keepAliveTime = 0 该参数默认对核心线程无效，而FixedThreadPool全部为核心线程；
     * workQueue 为LinkedBlockingQueue（无界阻塞队列），队列最大值为Integer.MAX_VALUE。
     * 如果任务提交速度持续大余任务处理速度，会造成队列大量阻塞。因为队列很大，很有可能在拒绝策略前，内存溢出。是其劣势；
     * FixedThreadPool的任务执行是无序的；
     * 适用场景：可用于Web服务瞬时削峰，但需注意长时间持续高峰情况造成的队列阻塞。
     *
     * @param nThreads
     * @return
     */
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());
    }

    /**
     * corePoolSize = 0，maximumPoolSize = Integer.MAX_VALUE，即线程数量几乎无限制；
     * keepAliveTime = 60s，线程空闲60s后自动结束。
     * workQueue 为 SynchronousQueue 同步队列，这个队列类似于一个接力棒，入队出队必须同时传递，
     * 因为CachedThreadPool线程创建无限制，不会有队列等待，所以使用SynchronousQueue；
     * 适用场景：快速处理大量耗时较短的任务，如Netty的NIO接受请求时，可使用CachedThreadPool。
     *
     * @return
     */
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                60L, TimeUnit.SECONDS,
                new SynchronousQueue<Runnable>());
    }

//    public static ExecutorService newSingleThreadExecutor() {
//        FinalizableDelegatedExecutorService finalizableDelegatedExecutorService = new FinalizableDelegatedExecutorService
//                (new ThreadPoolExecutor(1, 1,
//                        0L, TimeUnit.MILLISECONDS,
//                        new LinkedBlockingQueue<Runnable>()));
//        return finalizableDelegatedExecutorService;
//    }

}
